#define MSROUTER_C
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <net/route.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <net/if.h>       /* ifreq struct */
#include <netdb.h>
//set start flag
#include <libmscommon/mscommon.h>
#include <libmscommon/msstring.h>
#include <libmscommon/mscjson.h>
#include <libmscommon/msmd.h>
#include <libmslog/mslog.h>
#include "msrouter.h"

#define FLAG "ROUTER"

#define ms_dbroute    	"/etc/mscore/db/msdb_route.db"

ROUTERCOntext route_ctt;
typedef enum{
	RTACTION_ADD=0x01,
	RTACTION_DEL,
	RTACTION_SHOW ,
}RTACTION;
/* print usage information */
void usage()
{
    printf("IPv4 Command: route -A inet add/del -net/-host TARGET netmask "
            "NETMASK gw GETWAY dev DEVICE mtu MTU\n");
    printf("IPv6 Command: route -A inet6 add/del -net TARGET/PREFIX "
            "gw GETWAY dev DEVICE mtu MTU\n");
    return ;
}

/*
 *  IPv4 add/del route item in route table
 */
int inet_setroute(RTACTION action, char *args)
{
	struct sockaddr_in *addr;
	struct rtentry route;  
	memset((char *)&route, 0x00, sizeof(route));
	/* default target is net (host)*/
	route.rt_flags = RTF_UP ;
	
	ms_string str_array_item[256];
	int num=msstr_api_split(args, " ", str_array_item);
	int index=0;
	for(index=0;index<num;index++){
		if(ms_strncmp_saeq(str_array_item[index], "-net")){
			addr = (struct sockaddr_in*) &route.rt_dst;
			addr->sin_family = AF_INET;
			addr->sin_addr.s_addr = inet_addr(str_array_item[index+1]);
		}else if(!strcmp(str_array_item[index], "-host")){/* target is a host */
			addr = (struct sockaddr_in*) &route.rt_dst;
			addr->sin_family = AF_INET;
			addr->sin_addr.s_addr = inet_addr(str_array_item[index+1]);
			route.rt_flags |= RTF_HOST;
		}else if(!strcmp(str_array_item[index], "netmask")){/* netmask setting */
			addr = (struct sockaddr_in*) &route.rt_genmask;
			addr->sin_family = AF_INET;
			addr->sin_addr.s_addr = inet_addr(str_array_item[index+1]);
		}else if(!strcmp(str_array_item[index], "gw") || !strcmp(str_array_item[index], "gateway")){
			addr = (struct sockaddr_in*) &route.rt_gateway;
			addr->sin_family = AF_INET;
			addr->sin_addr.s_addr = inet_addr(str_array_item[index+1]);
			route.rt_flags |= RTF_GATEWAY;
		}else if(!strcmp(str_array_item[index], "device") || !strcmp(str_array_item[index], "dev")){/* device setting */
			route.rt_dev = str_array_item[index+1];
		}else if(!strcmp(str_array_item[index], "mtu")){
			route.rt_flags |= RTF_MTU;
			route.rt_mtu = atoi(str_array_item[index+1]);
		}
	}
	
	/* create a socket */
	int skfd = socket(AF_INET, SOCK_DGRAM, 0);
    	if(skfd < 0){
		close(skfd);
		ms_errRet(-1, "Create socket failed");
	}

	switch(action){
		case RTACTION_DEL:
			if(ioctl(skfd, SIOCDELRT, &route) < 0){
				close(skfd);
				ms_errRet(-1, "SIOCDELRT failed");
        			}
			break;
		case RTACTION_ADD:
			if(ioctl(skfd, SIOCADDRT, &route) < 0){
				close(skfd);
				ms_errRet(-1, "SIOCADDRT failed");
			}
			break;
	}
	(void) close(skfd);
	return 0;
}

static void msroute_api_setHost(char * host_addr,char *interface_name)
{
	char cmdbuf[512]={0};
	ms_sprintfs(cmdbuf, "route | grep %s", host_addr);
	if(0==ms_cmdIsGrep(cmdbuf)){
		ms_sprintfs(cmdbuf, "-host %s dev %s", host_addr,interface_name);
		inet_setroute(RTACTION_ADD, cmdbuf);
		
	}
}
void msroute_api_setMulticastHost(char * source_addr,char * multicast_addr,char *interface_name)
{
	msroute_api_setHost(source_addr,interface_name);
	msroute_api_setHost(multicast_addr,interface_name);
}
char msroute_api_readDB(ROUTERCOntext *route_ctt,char *dbname)
{
	char json_buf[40960]={0};
	if(msmd_api_read2(dbname, json_buf, sizeof(json_buf))<0){
		ms_errRet(-1,"msmd_api_read2");
	}
	cJSON *root = cJSON_Parse(json_buf);
	if(!root) {
		ms_errRet(-1,"Get root faild");
	}
	cJSON *js_multicasthost_arry= cJSON_GetObjectItem(root, str_multicasthost);
	if(!js_multicasthost_arry) {
		ms_errRet(-1,"no %s",str_multicasthost);
	}
	
	cJSON *js_item=ms_null;
	route_ctt->multicasthost_num=cJSON_GetArraySize(js_multicasthost_arry);//\u6570\u7ec4\u5927\u5c0f  
        	cJSON *js_multicasthost=js_multicasthost_arry->child;
	char multicasthost_index=0;
	while(js_multicasthost!=ms_null)  {  
		MULTICASTHOSTCOntext *multicasthost_ctt=&route_ctt->multicasthost_ctt[multicasthost_index];
		MSJSON_PARSE_STRING(js_item,js_multicasthost,str_mh_sourceaddr, multicasthost_ctt->source_addr);
		MSJSON_PARSE_STRING(js_item,js_multicasthost,str_mh_multicastaddr, multicasthost_ctt->multicast_addr);
		MSJSON_PARSE_STRING(js_item,js_multicasthost,str_mh_interfacename, multicasthost_ctt->interface_name);
		multicasthost_index++;
		js_multicasthost=js_multicasthost->next;  
        }  
	return 0;
}
char msroute_api_writeDB(ROUTERCOntext *route_ctt,char *dbname)
{

	cJSON * json_root = cJSON_CreateObject();
	if(NULL == json_root){
		ms_errRet(-1,"Create json_root failed");
	}

	cJSON * js_multicasthost_arry= cJSON_CreateArray();
	cJSON_AddItemToObject(json_root, str_multicasthost, js_multicasthost_arry);
	char multicasthost_index=0;
	for(multicasthost_index=0;multicasthost_index<route_ctt->multicasthost_num;multicasthost_index++){
		MULTICASTHOSTCOntext *multicasthost_ctt=&route_ctt->multicasthost_ctt[multicasthost_index];
		cJSON * js_multicasthost =cJSON_CreateObject();
		cJSON_AddItemToArray(js_multicasthost_arry,js_multicasthost);	
		MSJSON_BUILD_STRING(js_multicasthost, str_mh_sourceaddr, multicasthost_ctt->source_addr);
		MSJSON_BUILD_STRING(js_multicasthost, str_mh_multicastaddr, multicasthost_ctt->multicast_addr);
		MSJSON_BUILD_STRING(js_multicasthost, str_mh_interfacename, multicasthost_ctt->interface_name);
	}

	char * json_string = cJSON_Print(json_root);
	cJSON_Delete(json_root);
	if(NULL==json_string){
		ms_errRet(-1,"cJSON_Print failed");
	}
	msmd_api_writeProtect(dbname, json_string, strlen(json_string));
	free(json_string);
	return 0;
}

char msroute_api_check(ROUTERCOntext *route_ctt)
{
	char multicasthost_index=0;
	for(multicasthost_index=0;multicasthost_index<route_ctt->multicasthost_num;multicasthost_index++){
		MULTICASTHOSTCOntext *multicasthost_ctt=&route_ctt->multicasthost_ctt[multicasthost_index];
		msroute_api_setMulticastHost(multicasthost_ctt->source_addr,multicasthost_ctt->multicast_addr,multicasthost_ctt->interface_name);
	}
	return 0;
}
char msroute_api_init(ROUTERCOntext *route_ctt)
{
	memset(route_ctt,0,sizeof(ROUTERCOntext));
	ms_system("mkdir -p /etc/mscore/db/");
	if(0==msroute_api_readDB(route_ctt,ms_dbroute)){
		msroute_api_check(route_ctt);
	}
	return 0;
}
#undef MSROUTER_C
